/*
@title: Arrow
@description: Control an arrow to dodge flying objects and hazards
@author: AmazinAxel
@tags: ["avoid", "dodge", "fast-paced", "levels", "difficult"]
@addedOn: 2025-09-19
*/

/*
  Arrow:
  - You're an arrow trying to dodge flying objects!
  - Levels get harder w/ more hazards as you progress
  - Use WASD for movement
  - This game is VERY difficult - when encountering missiles, go from top-to-bottom as slowly as possible!
*/

const player = "p"
const warning = "w"
const bird = "b"
const debris = "d"
const plane = "P"
const missile = "m"

setLegend(
  [ player, bitmap`
................
................
................
................
....3333........
...39999333.....
...3999999933...
...39999999993..
...39999999993..
...3999999933...
...39999333.....
....3333........
................
................
................
................` ],   // Arrow character
  [ debris, bitmap`
................
................
................
................
......0.90C.....
....0CC9C0......
.....CC0CC......
....C.CC0C9.....
....CCCCCC0.....
....000CCCC.....
.....C9..C0.....
.....CC0CC......
................
................
................
................` ],   // Very slow
  [ bird, bitmap`
................
................
........0.......
.......00.......
......0000......
......0000......
......0000..0...
....000000000...
...0000000000...
......0000..0...
......0000......
......000.......
.......00.......
........0.......
................
................` ],     // Slow
  [ plane, bitmap`
................
.........7......
........77....7.
........77...77.
.......777...77.
.......777...77.
....77777777777.
...777777777777.
..777.7.7.7.7.7.
...777777777777.
....7777777777..
.......777......
........77......
........77......
.........7......
................` ],    // Fast
  [ warning, bitmap`
.......99.......
......9669......
......9669......
.....966669.....
.....966669.....
....96633669....
....96633669....
....96633669....
...9666336669...
...9666336669...
..966666666669..
..966666666669..
.96666633666669.
.96666633666669.
9666666666666669
9999999999999999` ],  // Missile indicator
  [ missile, bitmap`
................
................
................
9999999999999999
9999999999999999
3333333333333333
3333333333333333
3333333333333333
3333333333333333
3333333333333333
3333333333333333
9999999999999999
9999999999999999
................
................
................` ]   // Map-blocking sprite
);

const levelEnemies = { // Level enemy configs
  1: [ spawnBird ],
  2: [ spawnBird, spawnPlane ],
  3: [ spawnBird, spawnPlane, spawnPlane ],
  4: [ spawnBird, spawnPlane, spawnPlane, spawnPlane, spawnPlane, spawnMissile ],
  5: [ spawnBird, spawnPlane, spawnPlane, spawnPlane, spawnMissile ],
  6: [ spawnPlane, spawnPlane, spawnPlane, spawnMissile ],
  7: [ spawnPlane, spawnPlane, spawnMissile ],
  8: [ spawnPlane, spawnMissile ]
};

let game = {
  tick: 0,
  level: 0,
  gameOver: false
};
setMap(map`
...........
...........
...........
...........
.p.........
...........
...........
...........
...........`);

// Main game
function gameLoop() {
  // New level
  if ((game.tick % 150) === 0) {
    (game.level == 8)
    ? gameWin()
    : newLevel(game.level + 1)
  };

  // Update birds
  if ((game.tick % 10) === 0) {
    getAll(bird).forEach(birdSprite =>
      (birdSprite.x == 0)
      ? birdSprite.remove()
      : birdSprite.x -= 1
    )
  };
  
  // Update planes
  if ((game.tick % 5) === 0) {
    getAll(plane).forEach(planeSprite =>
      (planeSprite.x == 0)
      ? planeSprite.remove()
      : planeSprite.x -= 1
    )
  };

  // Spawn random new enemy
  if ((game.tick % 10) === 0) {
    const enemiesOnLevel = levelEnemies[game.level];
    enemiesOnLevel[Math.floor(Math.random() * enemiesOnLevel.length)]()
  };

  // Check if player is inside bird/plane
  const playerTile = getTile(getFirst(player).x, getFirst(player).y);
  if (playerTile.length > 1) 
     gameLose()
  
  // Iterate
  game.tick++;
  if (!game.gameOver)
     setTimeout(gameLoop, 20);
};

const getRandomY = () => Math.floor(Math.random() * 9);
function spawnBird() { addSprite(10, getRandomY(), bird) };
function spawnPlane() { addSprite(10, getRandomY(), plane) };
function spawnMissile() {
  const y = getFirst(player).y;
  addSprite(10, y, warning);

  setTimeout(() => { // Spawn missile blockoff
    getAll(warning).pop().remove()
    for (let i = 0; i <= 10; i++)
      addSprite(i, y, missile)
  }, 2000);

  setTimeout(() => { // Remove missile blockoff
    for (let i = 0; i <= 10; i++)
      getFirst(missile).remove()
  }, 4000);
};

function gameWin() {
  levelText = addText("You won!", { x: 6, y: 7 });
  game.gameOver = true;
};
function gameLose() {
  levelText = addText("You lost! ;(", { x: 4, y: 7 });
  game.gameOver = true;
};
function newLevel(level) {
  clearText();
  addText("Level: " + level, { x: 6, y: 1 });
  game.level = level;
};

// Controls & start gameloop
onInput("w", () => { if (!game.gameOver) getFirst(player).y -= 1});
onInput("a", () => { if (!game.gameOver) getFirst(player).x -= 1});
onInput("s", () => { if (!game.gameOver) getFirst(player).y += 1});
onInput("d", () => { if (!game.gameOver) getFirst(player).x += 1});
gameLoop();
